Python之路 - 函数
介绍 🍀
函数是组织好的 , 可重复使用的 , 用来实现单一 , 或相关联功能的代码段
函数能提高应用的模块性 , 和代码的重复利用率 , 比如我们一直使用的print()
, input()
等等 , 都是函数
如下我们写了一个用户认证程序 ; 而现在我们又需要写一个用户管理系统 , 管理系统中有很多的功能 , 比如添加用户 , 删除用户 , 查询用户 , 修改用户 ; 但是这些功能必须先通过用户认证程序才能使用 , 明显我们不可能在每一个功能前加上一段用户认证代码 , 因为这将大大增加我们的重复代码
那么为了解决这个问题我们就可以将用户认证功能封装到一个函数之中 , 而后续我们如果需要使用这个函数仅需调用即可 , 着就是函数的魅力所在 , 当然更多的还是通过下面进一步了解函数
语法 🍀
1 | # 自定义函数,function_name为函数名 |
简单实例
1 | def hello(): |
注意 : 上述仅为定义函数 , 函数并不会执行 , 只有当函数被调用时 , 函数内部代码才会执行
函数调用 🍀
函数调用通过函数名后加()
进行调用 , 如下 :
1 | # 定义函数 |
既然函数调用是通过函数名后加括号 , 在这个固定语法之中前者函数名又是什么? 如下 :
1 | # 定义函数 |
我们可以发现 , 函数名打印出来的是一个内存地址 , 由此不难理解 :
函数名相当于一个变量 , 而变量的值就是该函数本身所在的内存地址 ; 也就是说函数名实际上就是一个指针 , 它与函数本身存在一个映射关系
参数说明 🍀
形参: 变量只有在被调用时才分配内存单元 , 在调用结束时 , 即刻释放所分配的内存单元 ; 因此 , 形参只在函数内部有效 , 函数调用结束返回主调用函数后则不能再使用该形参变量
实参: 可以是常量、变量、表达式、函数等 , 无论实参是何种类型的量 , 在进行函数调用时 , 它们都必须有确定的值 , 以便把这些值传送给形参 ; 因此应预先用赋值 , 输入等办法使参数获得确定值
实参角度
1.位置参数: 位置参数要求从前至后一一对应
2.关键字传参: 形参和实参的参数名要求一致,但是顺序不做要求..但是实参和形参的数量也必须要一一对应
3.混合传参: 既有位置参数,又有关键字参数.但是关键字参数必须要在位置参数后面
1 | # 定义函数func |
位置参数 : 即参数必须以正确的顺序传入函数 , 传入的数量必须和声明的一样 , 不一样就报错
1 | # 用户登录验证 |
默认参数 🍀
调用时不指定就以默认值传入 , 指定则按指定值传入
1 | # 同时定义位置参数和默认参数 |
注:通过默认参数,我们就算不传参数也不会报错 , 即province
默认为"北京"
关键字参数 🍀
正常情况下 , 给函数传参数的时候要按照顺序传 , 如果不想按照顺序就可以使用关键参数
1 | def add_userinfo(name,age,province="北京"): |
非固定参数(混合参数) 🍀
当我们想要传入多个参数 , 但是我们又不确定的时候就可以使用非固定参数 ; 非固定参数有两个 , 一个 *args (元组形式)
以及 **kwargs (字典形式)
1 | # 设定两个非固定参数 |
对于非固定参数 , 其主要在于*
号 , *
号的作用是进行打包与解包 :
一个
*
号 , 则表示打包成元组或者将元组进行解包 , 过程如下 :1
2
3
4
5
6
7
8
9
10
11
12
13def main(n,*args):
return args
# 传递参数,第一个参数被认为是位置参数n,余后参数*号将会对其进行打包成元组,但参数形式必须符合元组规范
result = main(1,2,3,4,5)
print(result)
'''
执行结果:
(2, 3, 4, 5)
'''
'''
额外说明:
传递参数时,*号将参数封装成一个元组,即元组args
'''两个
**
号 , 则表示打包成字典或者将字典进行解包 , 过程如下 :1
2
3
4
5
6
7
8
9
10
11
12
13def main(**kwargs):
return kwargs
# 传递参数,**号将会对其进行打包成字典,但参数形式必须符合字典规范,即必须key-value
result = main(n2=2,n3=3,n4=4)
print(result)
'''
执行结果:
{'n4': 4, 'n2': 2, 'n3': 3}
'''
'''
额外说明:
传递参数时,**号将参数封装成一个字典,即字典kwargs
'''两者的解包如下 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26# 进行打包
def main(*args,**kwargs): # 参数状态:(1,2,3,4,5){'n1':1,'n2':2,'n3'=3}
# 进行解包
return (*args),{**kwargs} # 参数状态:1,2,3,4,5,n1=1,n2=2,n3=3
result = main(1,2,3,4,5,n1=1,n2=2,n3=3)
print(result)
'''
执行结果:
(1, 2, 3, 4, 5, {'n2': 2, 'n3': 3, 'n1': 1})
'''
# 解包补充
'''只要是可迭代对象我们都可以对其进行解包,如下'''
mytuple = (1,2,3,4,5,6,7)
# _为占位符,*c打包成列表
a,_,b,*c,d = mytuple
print(a)
print(b)
print(c)
print(d)
'''
执行结果:
1
3
[4, 5, 6]
7
'''形参中的*和** 表示聚合,将聚合后的值赋值给args和kwargs
- 实参中的*和** 表示打散,其中*表示将多个可迭代的对象拆分(l1,l2,l3),然后依次传递给形参的args.其中**表示将多个可迭代的字典拆分,然后依次传递给形参的**kwargs
1 | # 例子1: |
参数顺序及组合 🍀
参数顺序
在函数头部 (定义参数) : 一般参数 → 默认参数 → 非固定参数*args
→ 非固定参数**kwargs
在函数调用中 (传递参数) : 位置参数 → 关键字参数 → 默认参数 → 非固定参数*args
→ 非固定参数**kwargs
顺序依次如下:位置参数,*args,关键字参数,**args
1 | def func9(a,b,*args,sex='male',**kwargs): |
参数组合
在我们使用过程中 , 如果没有非固定参数 , 那么我们的关键参数或者默认参数可以用关键字进行传递 ; 如果有非固定参数 , 必须按照位置参数的方式进行传递
默认参数和非固定参数*args
位置可以进行调换 , 调换后默认参数传递需要加上关键字
全局与局部变量 🍀
局部变量:只在函数内部起作用的变量
全局变量:在整个程序中都起作用
1 | # 全局变量name |
总结 : 全局变量作用域是整个程序 , 局部变量作用域是定义该变量的子程序 ; 当全局变量与局部变量同名时 : 在定义局部变量的子程序内 , 局部变量起作用 ; 在其他地方全局变量起作用
global语句 : 可以将局部变量变成全局变量 , 在函数内部变量前加上 global 即可如 : global name
return语句 🍀
return
语句用于返回函数的执行结果 , 比如操作类函数一般都不需要返回值 , 当然可由我们的需要自己进行设定
不使用return
即返回None , 没有返回值
我们函数在执行过程中如果遇到return语句 , 就会结束并返回结果
1 | def sum( arg1, arg2 ): |
如果我们返回函数名
1 | def func(): |
这是一处妙用 , 当然在单层函数中作用不明显 , 下一章的《Python之路 - 函数进阶》中的闭包可以让你体会魅力之所在